Packages

library(tidyverse)
library(readxl)
library(lme4)
library(lmerTest)

Import Data and Wrangling (sorted by dataset)

Emerald Ash Borer Data

raw_eab_data <- read_excel("emerald-ash-borer-surveillance-data-2002-to-2020-en.xlsx")

# change column names from all uppercase to all lowercase to make it easier to work with
colnames(raw_eab_data) <- c("latitude", "longitude", "survey", "year",
                            "province", "community", "result")

# separate dataset for Ontario only and keep only necessary columns
ont_eab_data <- raw_eab_data %>% subset(province == "ONTARIO")
ont_eab_data <- ont_eab_data[, c(1, 2, 4, 6, 7)]

# remove NAs from community for future matching
ont_eab_data <- ont_eab_data %>% subset(!is.na(community))

Some of community names in our EAB data include designations that are common to more than one community (ex. County, District, etc) and although some of the census data names also have this feature, we can’t guess whether the corresponding communities will be formatted the same way (ex. will “Bruce County” in our EAB data be written as “Bruce” or “Bruce County” in the census?). However, the designation may help us in our report later on when we have to talk about the different communities. That’s why instead of changing our existing community names, I created a new column of the names with the designations removed. We will also do the same thing to the census data after downloading it.

Population Density Data

To determine whether the communities in our EAB data are urban or rural, we decided to use the Canadian 2021 census from Statistics Canada. We found a dataset containing only census information for population centres in Canada. According to StatCan, population centres are communities that have a population of at least 1000 people and a population density of at least 400 people per square kilometre. Locations that don’t meet these requirements are considered rural. If the communities from our EAB data are found in the population centres data, we can identify them as urban, and if they are missing, they will be rural. Since the dataset is for all of Canada, we will also subset to only population centres in Ontario.

# download census 2021 data for population centres and unzip file
temp <- tempfile() 
download.file("https://www150.statcan.gc.ca/n1/tbl/csv/98100011-eng.zip", temp)
trying URL 'https://www150.statcan.gc.ca/n1/tbl/csv/98100011-eng.zip'
Content type 'application/zip' length 94350 bytes (92 KB)
==================================================
downloaded 92 KB
census_2021_pop_centres <- read.csv(unz(temp, "98100011.csv"))
unlink(temp)
# subset dataframe to Ontario only and 
# keep name, population, and population density columns
## to exclude the rows for the provinces themselves, the chosen rows are
## 1 after the Ontario row and 1 before the Manitoba row
census_2021_pop_centres <- census_2021_pop_centres[380:681, c(2, 3, 5, 17)]

# simplify column names
colnames(census_2021_pop_centres) <- c("community_name", "DGUID", 
                                       "population_2021", "pop_density_2021")


# new column with designations removed
census_2021_pop_centres <- census_2021_pop_centres %>% 
  filter(!is.na(community_name)) %>% 
  mutate(community_name_2 = str_replace_all(census_2021_pop_centres$community_name,
                        c(" County" = "", " District" = "", " Division" = "", 
                          " Regional Municipality" = "", " Municipality" = "")))

Now that we have data for the urban communities, the next step is to match the community names from our EAB data to the census data and determine the community type. We made an empty column ‘community_type’ in our EAB data so that we can use a for loop to populate it.

ont_eab_data$community_type <- NA  # new column for community type

for (i in 1:nrow(ont_eab_data)) {  # look through every row in our EAB data
  
  j <- which(tolower(ont_eab_data$community_2[i]) == 
             tolower(census_2021_pop_centres$community_name_2))
  # find this row's community in column of census data community names
  # searching for identical names -> NO partial matches
  # returns row number of matching name or integer (0) if no matching name found
  
  if (!identical(j, integer (0))) {   # if row number returned
    ont_eab_data$community_type[i] <- "urban"
    
  } else {
    ont_eab_data$community_type[i] <- "rural"
    
  }
    
  
}

Temperature Data

ont_eab_data$avg_temp <- NA  # new column for temperature

for (i in 1:nrow(ont_eab_data)) {  # look through every row in our EAB data
  
  k <- which(tolower(ont_eab_data$community[i]) == 
             tolower(temperature_data$Community))
  # return row number of matching community name
  
  ont_eab_data$avg_temp[i] <- temperature_data$Avg_Temp[k]
      
      
}

Methods

Model 1: Time

Has EAB abundance changed over the years in different Ontario communities?

  • Number of observations for each community differ
  • Locations within each community are different (with some same locations between years)
anova(time_community_model, test="Chi")
Analysis of Deviance Table

Model: binomial, link: logit

Response: as.factor(result)

Terms added sequentially (first to last)

                Df Deviance Resid. Df Resid. Dev Pr(>Chi)    
NULL                            38000     8649.4             
year             1     0.40     37999     8649.0   0.5271    
community      153  2255.84     37846     6393.1   <2e-16 ***
year:community 106   366.14     37740     6027.0   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova(time_glm_model, test = "Chi")
Analysis of Deviance Table

Model: binomial, link: logit

Response: as.factor(result)

Terms added sequentially (first to last)

     Df Deviance Resid. Df Resid. Dev Pr(>Chi)
NULL                 38000     8649.4         
year  1  0.40001     37999     8649.0   0.5271

Model 2: Latitude and Longitude

# effect of latitude and longitude and their interaction on EAB detection
coordinates_glm_model <- glm(as.factor(result)~year * latitude * longitude, 
                             family = binomial, data = ont_eab_data)
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(coordinates_glm_model)

Call:
glm(formula = as.factor(result) ~ year * latitude * longitude, 
    family = binomial, data = ont_eab_data)

Coefficients:
                          Estimate Std. Error z value Pr(>|z|)    
(Intercept)              4.469e+05  2.656e+04   16.82   <2e-16 ***
year                    -2.221e+02  1.319e+01  -16.84   <2e-16 ***
latitude                -9.534e+03  5.867e+02  -16.25   <2e-16 ***
longitude                5.387e+03  3.146e+02   17.12   <2e-16 ***
year:latitude            4.738e+00  2.911e-01   16.27   <2e-16 ***
year:longitude          -2.677e+00  1.562e-01  -17.14   <2e-16 ***
latitude:longitude      -1.150e+02  6.954e+00  -16.54   <2e-16 ***
year:latitude:longitude  5.716e-02  3.450e-03   16.57   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 8649.4  on 38000  degrees of freedom
Residual deviance: 8014.2  on 37993  degrees of freedom
AIC: 8030.2

Number of Fisher Scoring iterations: 9

Is there a relationship between coordinates and community type?

# latitude and longitude and their interaction on community type
coord_type_model <- glm(as.factor(community_type)~latitude * longitude, 
                        family = binomial, data = ont_eab_data)
summary(coord_type_model)

Call:
glm(formula = as.factor(community_type) ~ latitude * longitude, 
    family = binomial, data = ont_eab_data)

Coefficients:
                     Estimate Std. Error z value Pr(>|z|)    
(Intercept)        -3.366e+02  1.453e+01  -23.16   <2e-16 ***
latitude            7.006e+00  3.055e-01   22.93   <2e-16 ***
longitude          -3.828e+00  1.747e-01  -21.91   <2e-16 ***
latitude:longitude  7.952e-02  3.665e-03   21.70   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 33928  on 38000  degrees of freedom
Residual deviance: 30269  on 37997  degrees of freedom
AIC: 30277

Number of Fisher Scoring iterations: 4

Is there a relationship between coordinates and mean temperature?

# latitude and longitude and their interaction on mean temperature
coord_temp_model <- lm(avg_temp ~ latitude * longitude, data = ont_eab_data)
summary(coord_temp_model)

Call:
lm(formula = avg_temp ~ latitude * longitude, data = ont_eab_data)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.2880 -0.3075  0.2186  0.4849  6.3558 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)        -2.144e+02  4.678e+00  -45.83   <2e-16 ***
latitude            4.401e+00  9.987e-02   44.07   <2e-16 ***
longitude          -3.344e+00  5.596e-02  -59.76   <2e-16 ***
latitude:longitude  6.804e-02  1.192e-03   57.08   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8742 on 37997 degrees of freedom
Multiple R-squared:  0.8355,    Adjusted R-squared:  0.8355 
F-statistic: 6.435e+04 on 3 and 37997 DF,  p-value: < 2.2e-16

Model 3: Community Type

# effect of community type on EAB abundance
types_result <- table(ont_eab_data$community_type, ont_eab_data$result)
types_result
       
        DETECTED NOT DETECTED
  rural      458        31307
  urban      460         5776
chisq.test(ont_eab_data$community_type, ont_eab_data$result, correct = F)

    Pearson's Chi-squared test

data:  ont_eab_data$community_type and ont_eab_data$result
X-squared = 778.8, df = 1, p-value < 2.2e-16
# effect of community type on EAB detection over the years
type_model <- glm(as.factor(result)~year * community_type, 
                  family = binomial, data = ont_eab_data)
summary(type_model)

Call:
glm(formula = as.factor(result) ~ year * community_type, family = binomial, 
    data = ont_eab_data)

Coefficients:
                           Estimate Std. Error z value Pr(>|z|)    
(Intercept)               240.25054   26.60605   9.030   <2e-16 ***
year                       -0.11766    0.01326  -8.873   <2e-16 ***
community_typeurban      -444.33419   35.84048 -12.398   <2e-16 ***
year:community_typeurban    0.22066    0.01787  12.349   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 8649.4  on 38000  degrees of freedom
Residual deviance: 7920.9  on 37997  degrees of freedom
AIC: 7928.9

Number of Fisher Scoring iterations: 7

Model 4: Temperature

temp_model <- glm(as.factor(result)~avg_temp, 
                  family = binomial, data = ont_eab_data)
summary(temp_model)

Call:
glm(formula = as.factor(result) ~ avg_temp, family = binomial, 
    data = ont_eab_data)

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  5.55926    0.21630  25.702   <2e-16 ***
avg_temp    -0.20102    0.02241  -8.969   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 8649.4  on 38000  degrees of freedom
Residual deviance: 8545.3  on 37999  degrees of freedom
AIC: 8549.3

Number of Fisher Scoring iterations: 7

Model 5: Community Type and Temperature Model

summary(temp_type_model)

Call:
glm(formula = as.factor(result) ~ avg_temp * community_type, 
    family = binomial, data = ont_eab_data)

Coefficients:
                             Estimate Std. Error z value Pr(>|z|)    
(Intercept)                   4.47027    0.27186  16.443  < 2e-16 ***
avg_temp                     -0.02670    0.02901  -0.921  0.35728    
community_typeurban           1.21434    0.38997   3.114  0.00185 ** 
avg_temp:community_typeurban -0.32738    0.04038  -8.108 5.15e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 8649.4  on 38000  degrees of freedom
Residual deviance: 7786.2  on 37997  degrees of freedom
AIC: 7794.2

Number of Fisher Scoring iterations: 7

Results

Model 1: Time

result_colour <- c("#FF0000", "#3333CC")

ggplot(ont_eab_data, aes(x = year, fill = result)) +
  geom_histogram(stat = "count") +
  scale_x_continuous(breaks = seq(2002, 2020, by = 2)) +
  theme_bw() +
  scale_fill_manual(values = result_colour) +
  labs(title = "EAB Detection Throughout Time", x = "Year", y = "Observation Count", fill = "Detection Result")
Warning: Ignoring unknown parameters: `binwidth`, `bins`, and `pad`

As you can see, the observations are skewed through the years. The greatest number of observations happened between the years 2003 and 2010, which corresponds with some of the first recorded incidences of the EAB in North America. The most-important takeaway from this graph is the frequency of observations within this dataset changed significantly more over time than the abundance of EABs did. Furthermore, this change in observation frequency over the years makes it harder to compare and contrast detection rate through the years.

Model 2: Latitude + Longitude

ggplot(ont_eab_data, aes(x = longitude, y = latitude, color = result)) +
  geom_point(size = 0.8, alpha = 0.6) +
  theme_bw() +
  scale_color_manual(values = result_colour) +
  labs(title = "EAB Detection in Ontario by Longitude & Latitude", x = "Longitude", y = "Latitude", color = "Detection Result")

EAB detection is concentrated in one general area!

ggplot(ont_eab_data, aes(x = longitude, y = latitude, color = community_type)) +
  geom_point(size = 0.8, alpha = 0.6) +
  theme_bw() +
  scale_color_manual(values = colour) +
  labs(title = "Community Type in Ontario by Longitude & Latitude", x = "Longitude", y = "Latitude", color = "Community Type")

There IS a correlation between coordinates and community type

ggplot(ont_eab_data, aes(x = longitude, y = latitude, color = avg_temp)) +
  geom_point(size = 1, alpha = 0.3) +
  theme_bw() +  
  labs(title = "Annual Average Temperature in Ontario by Longitude & Latitude", x = "Longitude", y = "Latitude", color = "Average Annual Temperature (˚C)")

Model 3: Community Type

ont_eab_data %>% 
  ggplot(aes(x = year, fill = community_type)) + 
  geom_histogram(binwidth = 1.2) + 
  facet_wrap(~result, scales = "free_y") +
  scale_x_continuous(breaks = seq(2002, 2020, by = 2)) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  scale_fill_manual(values = colour) +
  labs(title = "EAB Detection by Year and Community Type", x = "Year", y = "Number of Observations", 
       fill = "Community Type")

Note the differences in y-axis scales between “Detected” and “Not Detected”, as well as the significantly higher number of observations in the earlier half of the dataset.

ggplot(ont_eab_data, aes(x = result, y = year, fill = result)) + 
  geom_boxplot() + 
  geom_point(size = 0.6, alpha = 0.4) + facet_wrap(~community_type) +
  theme_bw() +
  scale_fill_manual(values = result_colour) +
  labs(title = "EAB Detection by Year and Community Type", x = "", y = "Year", fill = "Detection Result")

ggplot(ont_eab_data, aes(x = result, y = year, fill = result)) + 
  geom_violin() + 
  facet_wrap(~community_type) +
  theme_bw() +
  scale_fill_manual(values = result_colour) +
  labs(title = "EAB Detection by Year and Community Type", x = "", y = "Year", fill = "Detection Result")

ggplot(ont_eab_data, aes(x = community_type, y = year, fill = community_type)) + 
  geom_violin() + 
  facet_wrap(~result) +
  theme_bw() +
  scale_fill_manual(values = colour) +
  labs(title = "EAB Detection by Year and Community Type", x = "", y = "Year", fill = "Community Type")

ggplot(ont_eab_data, aes(x = year, y = community_type, fill = community_type)) + 
  geom_violin() + 
  facet_wrap(~result) +
  theme_bw() +
  scale_x_continuous(breaks = seq(2002, 2020, by = 2)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  scale_fill_manual(values = colour) +
  labs(title = "EAB Detection by Year and Community Type", x = "Year", y = "", fill = "Community Type")

Communities Dominating the Observations

community_count <- ont_eab_data %>% 
  count(community, wt = NULL, sort = TRUE)
total_dataframe <- cbind(temperature_data, community_count)
most_observations <- total_dataframe %>% 
  filter(n >= 200)

ggplot(most_observations, aes(x = community, y = n)) + 
  geom_point() +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  labs(x = "Community", y = "Observations per Community", title = "Number of Observations from Each Community (n ≥ 200)")

Chatham-Kent Division (rural)

ont_eab_data %>% 
  filter(community == "CHATHAM-KENT DIVISION") %>% 
ggplot(aes(x = year, fill = result)) +
  geom_histogram(stat = "count") +
  theme_bw() +
  scale_fill_manual(values = result_colour) +
  labs(title = "EAB Detection by Year in the Chatham-Kent Division", x = "Year", y = "Number of Observations", fill = "Detection Result")
Warning: Ignoring unknown parameters: `binwidth`, `bins`, and `pad`

Our dataset is dominated by a couple of communities especially during the early years of data collection.

Model 4: Temperature

ggplot(ont_eab_data, aes(x = year, y = avg_temp, color = result)) +
  geom_point() +
  geom_smooth(method = "glm", family = "binomial", se = FALSE) +
  scale_color_manual(values = result_colour) +
  theme_bw() +
  labs(title = "EAB Detection Through Time as a Function of Temperature", x = "Year", y = "Average Temperature (˚C)", color = "Detection Result")
Warning: Ignoring unknown parameters: `family`

Model 5: Community Type AND Temperature

ggplot(ont_eab_data, aes(x = year, y = avg_temp, color = result)) + 
  geom_point() +
  facet_wrap(~community_type) +
  theme_bw() +
  scale_x_continuous(breaks = seq(2002, 2020, by = 2)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  scale_color_manual(values = result_colour) +
  labs(title = "EAB Detection by Year, Temperature and Community Type", x = "Year", y = "Average Annual Temperature (˚C)", color = "Detection Result")

colour <- c(rural = "forestgreen", urban = "darkgrey")

ggplot(ont_eab_data, aes(x = year, y = avg_temp, color = community_type)) +
  geom_point() +
  facet_wrap(~result) +
  scale_color_manual(values = colour) +
  theme_bw() +
  geom_smooth(method = "lm", se = FALSE) +
  scale_x_continuous(breaks = seq(2002, 2020, by = 2)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  labs(title = "EAB Detection by Year, Temperature and Community Type", x = "Year", y = "Average Annual Temperature (˚C)", color = "Community Type")

kruskal.test(result ~ avg_temp*community,
             data = ont_eab_data)
Error in kruskal.test.formula(result ~ avg_temp * community, data = ont_eab_data) : 
  'formula' should be of the form response ~ group
temp_model <- glm(as.factor(result)~ avg_temp + (1|community), family = "binomial", data = ont_eab_data)
Error in 1 | community : 
  operations are possible only for numeric, logical or complex types
LS0tCnRpdGxlOiAiRUVCMzEzIFByb2plY3QiCmF1dGhvcjogIkdyb3VwIEciCm91dHB1dDoKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKIyMgUGFja2FnZXMKCmBgYHtyIHNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKYGBgCgoKIyBJbXBvcnQgRGF0YSBhbmQgV3JhbmdsaW5nIChzb3J0ZWQgYnkgZGF0YXNldCkKCiMjIEVtZXJhbGQgQXNoIEJvcmVyIERhdGEKCmBgYHtyIGRvd25sb2FkX0VBQl9kYXRhfQpyYXdfZWFiX2RhdGEgPC0gcmVhZF9leGNlbCgiZW1lcmFsZC1hc2gtYm9yZXItc3VydmVpbGxhbmNlLWRhdGEtMjAwMi10by0yMDIwLWVuLnhsc3giKQoKIyBjaGFuZ2UgY29sdW1uIG5hbWVzIGZyb20gYWxsIHVwcGVyY2FzZSB0byBhbGwgbG93ZXJjYXNlIHRvIG1ha2UgaXQgZWFzaWVyIHRvIHdvcmsgd2l0aApjb2xuYW1lcyhyYXdfZWFiX2RhdGEpIDwtIGMoImxhdGl0dWRlIiwgImxvbmdpdHVkZSIsICJzdXJ2ZXkiLCAieWVhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJvdmluY2UiLCAiY29tbXVuaXR5IiwgInJlc3VsdCIpCgojIHNlcGFyYXRlIGRhdGFzZXQgZm9yIE9udGFyaW8gb25seSBhbmQga2VlcCBvbmx5IG5lY2Vzc2FyeSBjb2x1bW5zCm9udF9lYWJfZGF0YSA8LSByYXdfZWFiX2RhdGEgJT4lIHN1YnNldChwcm92aW5jZSA9PSAiT05UQVJJTyIpCm9udF9lYWJfZGF0YSA8LSBvbnRfZWFiX2RhdGFbLCBjKDEsIDIsIDQsIDYsIDcpXQoKIyByZW1vdmUgTkFzIGZyb20gY29tbXVuaXR5IGZvciBmdXR1cmUgbWF0Y2hpbmcKb250X2VhYl9kYXRhIDwtIG9udF9lYWJfZGF0YSAlPiUgc3Vic2V0KCFpcy5uYShjb21tdW5pdHkpKQpgYGAKCgpTb21lIG9mIGNvbW11bml0eSBuYW1lcyBpbiBvdXIgRUFCIGRhdGEgaW5jbHVkZSBkZXNpZ25hdGlvbnMgdGhhdCBhcmUgY29tbW9uIHRvIG1vcmUgdGhhbiBvbmUgY29tbXVuaXR5IChleC4gQ291bnR5LCBEaXN0cmljdCwgZXRjKSBhbmQgYWx0aG91Z2ggc29tZSBvZiB0aGUgY2Vuc3VzIGRhdGEgbmFtZXMgYWxzbyBoYXZlIHRoaXMgZmVhdHVyZSwgd2UgY2FuJ3QgZ3Vlc3Mgd2hldGhlciB0aGUgY29ycmVzcG9uZGluZyBjb21tdW5pdGllcyB3aWxsIGJlIGZvcm1hdHRlZCB0aGUgc2FtZSB3YXkgKGV4LiB3aWxsICJCcnVjZSBDb3VudHkiIGluIG91ciBFQUIgZGF0YSBiZSB3cml0dGVuIGFzICJCcnVjZSIgb3IgIkJydWNlIENvdW50eSIgaW4gdGhlIGNlbnN1cz8pLiBIb3dldmVyLCB0aGUgZGVzaWduYXRpb24gbWF5IGhlbHAgdXMgaW4gb3VyIHJlcG9ydCBsYXRlciBvbiB3aGVuIHdlIGhhdmUgdG8gdGFsayBhYm91dCB0aGUgZGlmZmVyZW50IGNvbW11bml0aWVzLiBUaGF0J3Mgd2h5IGluc3RlYWQgb2YgY2hhbmdpbmcgb3VyIGV4aXN0aW5nIGNvbW11bml0eSBuYW1lcywgSSBjcmVhdGVkIGEgbmV3IGNvbHVtbiBvZiB0aGUgbmFtZXMgd2l0aCB0aGUgZGVzaWduYXRpb25zIHJlbW92ZWQuIFdlIHdpbGwgYWxzbyBkbyB0aGUgc2FtZSB0aGluZyB0byB0aGUgY2Vuc3VzIGRhdGEgYWZ0ZXIgZG93bmxvYWRpbmcgaXQuCgpgYGB7ciBlZGl0X2NvbW11bml0eV9uYW1lc30Kb250X2VhYl9kYXRhIDwtIG9udF9lYWJfZGF0YSAlPiUgCiAgbXV0YXRlKGNvbW11bml0eV8yID0gc3RyX3JlcGxhY2VfYWxsKG9udF9lYWJfZGF0YSRjb21tdW5pdHksCiAgICAgICAgICAgICAgICAgICAgICAgIGMoIiBDT1VOVFkiID0gIiIsICIgRElTVFJJQ1QiID0gIiIsICIgRElWSVNJT04iID0gIiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICIgUkVHSU9OQUwgTVVOSUNJUEFMSVRZIiA9ICIiLCAiIE1VTklDSVBBTElUWSIgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiIFVOSVRFRCBDT1VOVElFUyIgPSAiIikpKQpgYGAKCgojIyBQb3B1bGF0aW9uIERlbnNpdHkgRGF0YQoKVG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGNvbW11bml0aWVzIGluIG91ciBFQUIgZGF0YSBhcmUgdXJiYW4gb3IgcnVyYWwsIHdlIGRlY2lkZWQgdG8gdXNlIHRoZSBDYW5hZGlhbiAyMDIxIGNlbnN1cyBmcm9tIFN0YXRpc3RpY3MgQ2FuYWRhLiBXZSBmb3VuZCBhIGRhdGFzZXQgY29udGFpbmluZyBvbmx5IGNlbnN1cyBpbmZvcm1hdGlvbiBmb3IgcG9wdWxhdGlvbiBjZW50cmVzIGluIENhbmFkYS4gQWNjb3JkaW5nIHRvIFN0YXRDYW4sIHBvcHVsYXRpb24gY2VudHJlcyBhcmUgY29tbXVuaXRpZXMgdGhhdCBoYXZlIGEgcG9wdWxhdGlvbiBvZiBhdCBsZWFzdCAxMDAwIHBlb3BsZSBhbmQgYSBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgYXQgbGVhc3QgNDAwIHBlb3BsZSBwZXIgc3F1YXJlIGtpbG9tZXRyZS4gTG9jYXRpb25zIHRoYXQgZG9uJ3QgbWVldCB0aGVzZSByZXF1aXJlbWVudHMgYXJlIGNvbnNpZGVyZWQgcnVyYWwuIElmIHRoZSBjb21tdW5pdGllcyBmcm9tIG91ciBFQUIgZGF0YSBhcmUgZm91bmQgaW4gdGhlIHBvcHVsYXRpb24gY2VudHJlcyBkYXRhLCB3ZSBjYW4gaWRlbnRpZnkgdGhlbSBhcyB1cmJhbiwgYW5kIGlmIHRoZXkgYXJlIG1pc3NpbmcsIHRoZXkgd2lsbCBiZSBydXJhbC4gU2luY2UgdGhlIGRhdGFzZXQgaXMgZm9yIGFsbCBvZiBDYW5hZGEsIHdlIHdpbGwgYWxzbyBzdWJzZXQgdG8gb25seSBwb3B1bGF0aW9uIGNlbnRyZXMgaW4gT250YXJpby4KCmBgYHtyIGRvd25sb2FkX3VyYmFuX2RhdGF9CiMgZG93bmxvYWQgY2Vuc3VzIDIwMjEgZGF0YSBmb3IgcG9wdWxhdGlvbiBjZW50cmVzIGFuZCB1bnppcCBmaWxlCnRlbXAgPC0gdGVtcGZpbGUoKSAKZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly93d3cxNTAuc3RhdGNhbi5nYy5jYS9uMS90YmwvY3N2Lzk4MTAwMDExLWVuZy56aXAiLCB0ZW1wKQpjZW5zdXNfMjAyMV9wb3BfY2VudHJlcyA8LSByZWFkLmNzdih1bnoodGVtcCwgIjk4MTAwMDExLmNzdiIpKQp1bmxpbmsodGVtcCkKYGBgCgoKYGBge3Igc3Vic2V0dGluZ19jZW5zdXNfZGF0YX0KIyBzdWJzZXQgZGF0YWZyYW1lIHRvIE9udGFyaW8gb25seSBhbmQgCiMga2VlcCBuYW1lLCBwb3B1bGF0aW9uLCBhbmQgcG9wdWxhdGlvbiBkZW5zaXR5IGNvbHVtbnMKIyMgdG8gZXhjbHVkZSB0aGUgcm93cyBmb3IgdGhlIHByb3ZpbmNlcyB0aGVtc2VsdmVzLCB0aGUgY2hvc2VuIHJvd3MgYXJlCiMjIDEgYWZ0ZXIgdGhlIE9udGFyaW8gcm93IGFuZCAxIGJlZm9yZSB0aGUgTWFuaXRvYmEgcm93CmNlbnN1c18yMDIxX3BvcF9jZW50cmVzIDwtIGNlbnN1c18yMDIxX3BvcF9jZW50cmVzWzM4MDo2ODEsIGMoMiwgMywgNSwgMTcpXQoKIyBzaW1wbGlmeSBjb2x1bW4gbmFtZXMKY29sbmFtZXMoY2Vuc3VzXzIwMjFfcG9wX2NlbnRyZXMpIDwtIGMoImNvbW11bml0eV9uYW1lIiwgIkRHVUlEIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3B1bGF0aW9uXzIwMjEiLCAicG9wX2RlbnNpdHlfMjAyMSIpCgoKIyBuZXcgY29sdW1uIHdpdGggZGVzaWduYXRpb25zIHJlbW92ZWQKY2Vuc3VzXzIwMjFfcG9wX2NlbnRyZXMgPC0gY2Vuc3VzXzIwMjFfcG9wX2NlbnRyZXMgJT4lIAogIGZpbHRlcighaXMubmEoY29tbXVuaXR5X25hbWUpKSAlPiUgCiAgbXV0YXRlKGNvbW11bml0eV9uYW1lXzIgPSBzdHJfcmVwbGFjZV9hbGwoY2Vuc3VzXzIwMjFfcG9wX2NlbnRyZXMkY29tbXVuaXR5X25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGMoIiBDb3VudHkiID0gIiIsICIgRGlzdHJpY3QiID0gIiIsICIgRGl2aXNpb24iID0gIiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICIgUmVnaW9uYWwgTXVuaWNpcGFsaXR5IiA9ICIiLCAiIE11bmljaXBhbGl0eSIgPSAiIikpKQpgYGAKCgpOb3cgdGhhdCB3ZSBoYXZlIGRhdGEgZm9yIHRoZSB1cmJhbiBjb21tdW5pdGllcywgdGhlIG5leHQgc3RlcCBpcyB0byBtYXRjaCB0aGUgY29tbXVuaXR5IG5hbWVzIGZyb20gb3VyIEVBQiBkYXRhIHRvIHRoZSBjZW5zdXMgZGF0YSBhbmQgZGV0ZXJtaW5lIHRoZSBjb21tdW5pdHkgdHlwZS4gV2UgbWFkZSBhbiBlbXB0eSBjb2x1bW4gJ2NvbW11bml0eV90eXBlJyBpbiBvdXIgRUFCIGRhdGEgc28gdGhhdCB3ZSBjYW4gdXNlIGEgZm9yIGxvb3AgdG8gcG9wdWxhdGUgaXQuIAoKYGBge3IgbWF0Y2hfY29tbXVuaXR5X25hbWVzfQpvbnRfZWFiX2RhdGEkY29tbXVuaXR5X3R5cGUgPC0gTkEgICMgbmV3IGNvbHVtbiBmb3IgY29tbXVuaXR5IHR5cGUKCmZvciAoaSBpbiAxOm5yb3cob250X2VhYl9kYXRhKSkgeyAgIyBsb29rIHRocm91Z2ggZXZlcnkgcm93IGluIG91ciBFQUIgZGF0YQogIAogIGogPC0gd2hpY2godG9sb3dlcihvbnRfZWFiX2RhdGEkY29tbXVuaXR5XzJbaV0pID09IAogICAgICAgICAgICAgdG9sb3dlcihjZW5zdXNfMjAyMV9wb3BfY2VudHJlcyRjb21tdW5pdHlfbmFtZV8yKSkKICAjIGZpbmQgdGhpcyByb3cncyBjb21tdW5pdHkgaW4gY29sdW1uIG9mIGNlbnN1cyBkYXRhIGNvbW11bml0eSBuYW1lcwogICMgc2VhcmNoaW5nIGZvciBpZGVudGljYWwgbmFtZXMgLT4gTk8gcGFydGlhbCBtYXRjaGVzCiAgIyByZXR1cm5zIHJvdyBudW1iZXIgb2YgbWF0Y2hpbmcgbmFtZSBvciBpbnRlZ2VyICgwKSBpZiBubyBtYXRjaGluZyBuYW1lIGZvdW5kCiAgCiAgaWYgKCFpZGVudGljYWwoaiwgaW50ZWdlciAoMCkpKSB7ICAgIyBpZiByb3cgbnVtYmVyIHJldHVybmVkCiAgICBvbnRfZWFiX2RhdGEkY29tbXVuaXR5X3R5cGVbaV0gPC0gInVyYmFuIgogICAgCiAgfSBlbHNlIHsKICAgIG9udF9lYWJfZGF0YSRjb21tdW5pdHlfdHlwZVtpXSA8LSAicnVyYWwiCiAgICAKICB9CiAgICAKICAKfQpgYGAKCgojIyBUZW1wZXJhdHVyZSBEYXRhCgpgYGB7cn0KdGVtcGVyYXR1cmVfZGF0YSA8LSByZWFkX2V4Y2VsKCJFRUIzMTNfRUFCX3dlYXRoZXJfMS54bHN4IikKdGVtcGVyYXR1cmVfZGF0YSA8LSB0ZW1wZXJhdHVyZV9kYXRhWywxOjNdICMgcmVtb3ZlIHVubmVjZXNzYXJ5IGNvbHVtbnMKYGBgCgpgYGB7cn0Kb250X2VhYl9kYXRhJGF2Z190ZW1wIDwtIE5BICAjIG5ldyBjb2x1bW4gZm9yIHRlbXBlcmF0dXJlCgpmb3IgKGkgaW4gMTpucm93KG9udF9lYWJfZGF0YSkpIHsgICMgbG9vayB0aHJvdWdoIGV2ZXJ5IHJvdyBpbiBvdXIgRUFCIGRhdGEKICAKICBrIDwtIHdoaWNoKHRvbG93ZXIob250X2VhYl9kYXRhJGNvbW11bml0eVtpXSkgPT0gCiAgICAgICAgICAgICB0b2xvd2VyKHRlbXBlcmF0dXJlX2RhdGEkQ29tbXVuaXR5KSkKICAjIHJldHVybiByb3cgbnVtYmVyIG9mIG1hdGNoaW5nIGNvbW11bml0eSBuYW1lCiAgCiAgb250X2VhYl9kYXRhJGF2Z190ZW1wW2ldIDwtIHRlbXBlcmF0dXJlX2RhdGEkQXZnX1RlbXBba10KICAgICAgCiAgICAgIAp9CgpgYGAKCgojIyBNZXRob2RzCgojIyMgTW9kZWwgMTogVGltZQoKSGFzIEVBQiBhYnVuZGFuY2UgY2hhbmdlZCBvdmVyIHRoZSB5ZWFycyBpbiBkaWZmZXJlbnQgT250YXJpbyBjb21tdW5pdGllcz8KCiogTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgZWFjaCBjb21tdW5pdHkgZGlmZmVyCiogTG9jYXRpb25zIHdpdGhpbiBlYWNoIGNvbW11bml0eSBhcmUgZGlmZmVyZW50ICh3aXRoIHNvbWUgc2FtZSBsb2NhdGlvbnMgYmV0d2VlbiB5ZWFycykKCgpgYGB7cn0KIyBlZmZlY3Qgb2YgdGltZSBvbiBFQUIgYWJ1bmRhbmNlCnRpbWVfZ2xtX21vZGVsIDwtIGdsbShhcy5mYWN0b3IocmVzdWx0KX55ZWFyLCAKICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsLCBkYXRhID0gb250X2VhYl9kYXRhKQpzdW1tYXJ5KHRpbWVfZ2xtX21vZGVsKQoKCiMgZWZmZWN0IG9mIHRpbWUgb24gRUFCIGFidW5kYW5jZSBieSBjb21tdW5pdHkKdGltZV9jb21tdW5pdHlfbW9kZWwgPC0gZ2xtKGFzLmZhY3RvcihyZXN1bHQpfnllYXIgKiBjb21tdW5pdHksIAogICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwsIGRhdGEgPSBvbnRfZWFiX2RhdGEpCgphbm92YSh0aW1lX2NvbW11bml0eV9tb2RlbCwgdGVzdD0iQ2hpIikKYGBgCmBgYHtyfQphbm92YSh0aW1lX2dsbV9tb2RlbCwgdGVzdCA9ICJDaGkiKQpgYGAKCgojIyMgTW9kZWwgMjogTGF0aXR1ZGUgYW5kIExvbmdpdHVkZQoKYGBge3J9CiMgZWZmZWN0IG9mIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgYW5kIHRoZWlyIGludGVyYWN0aW9uIG9uIEVBQiBkZXRlY3Rpb24KY29vcmRpbmF0ZXNfZ2xtX21vZGVsIDwtIGdsbShhcy5mYWN0b3IocmVzdWx0KX55ZWFyICogbGF0aXR1ZGUgKiBsb25naXR1ZGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsLCBkYXRhID0gb250X2VhYl9kYXRhKQpzdW1tYXJ5KGNvb3JkaW5hdGVzX2dsbV9tb2RlbCkKYGBgCgoKIyMjIyBJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvb3JkaW5hdGVzIGFuZCBjb21tdW5pdHkgdHlwZT8KCmBgYHtyfQojIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgYW5kIHRoZWlyIGludGVyYWN0aW9uIG9uIGNvbW11bml0eSB0eXBlCmNvb3JkX3R5cGVfbW9kZWwgPC0gZ2xtKGFzLmZhY3Rvcihjb21tdW5pdHlfdHlwZSl+bGF0aXR1ZGUgKiBsb25naXR1ZGUsIAogICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeShjb29yZF90eXBlX21vZGVsKQpgYGAKCgojIyMjIElzIHRoZXJlIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gY29vcmRpbmF0ZXMgYW5kIG1lYW4gdGVtcGVyYXR1cmU/CgpgYGB7cn0KIyBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGFuZCB0aGVpciBpbnRlcmFjdGlvbiBvbiBtZWFuIHRlbXBlcmF0dXJlCmNvb3JkX3RlbXBfbW9kZWwgPC0gbG0oYXZnX3RlbXAgfiBsYXRpdHVkZSAqIGxvbmdpdHVkZSwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeShjb29yZF90ZW1wX21vZGVsKQpgYGAKCgojIyMgTW9kZWwgMzogQ29tbXVuaXR5IFR5cGUKCmBgYHtyfQojIGVmZmVjdCBvZiBjb21tdW5pdHkgdHlwZSBvbiBFQUIgYWJ1bmRhbmNlCnR5cGVzX3Jlc3VsdCA8LSB0YWJsZShvbnRfZWFiX2RhdGEkY29tbXVuaXR5X3R5cGUsIG9udF9lYWJfZGF0YSRyZXN1bHQpCnR5cGVzX3Jlc3VsdAoKY2hpc3EudGVzdChvbnRfZWFiX2RhdGEkY29tbXVuaXR5X3R5cGUsIG9udF9lYWJfZGF0YSRyZXN1bHQsIGNvcnJlY3QgPSBGKQoKIyBlZmZlY3Qgb2YgY29tbXVuaXR5IHR5cGUgb24gRUFCIGRldGVjdGlvbiBvdmVyIHRoZSB5ZWFycwp0eXBlX21vZGVsIDwtIGdsbShhcy5mYWN0b3IocmVzdWx0KX55ZWFyICogY29tbXVuaXR5X3R5cGUsIAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeSh0eXBlX21vZGVsKQpgYGAKCgojIyMgTW9kZWwgNDogVGVtcGVyYXR1cmUKCmBgYHtyfQp0ZW1wX21vZGVsIDwtIGdsbShhcy5mYWN0b3IocmVzdWx0KX55ZWFyICsgYXZnX3RlbXAsIAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeSh0ZW1wX21vZGVsKQpgYGAKICAKCiMjIyBNb2RlbCA1OiBDb21tdW5pdHkgVHlwZSBhbmQgVGVtcGVyYXR1cmUgTW9kZWwKCmBgYHtyfQp0ZW1wX3R5cGVfbW9kZWwgPC0gZ2xtKGFzLmZhY3RvcihyZXN1bHQpfmF2Z190ZW1wICogY29tbXVuaXR5X3R5cGUsIAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeSh0ZW1wX3R5cGVfbW9kZWwpCmBgYAoKCiMjIFJlc3VsdHMKCiMjIyBNb2RlbCAxOiBUaW1lCgpgYGB7cn0KcmVzdWx0X2NvbG91ciA8LSBjKCIjRkYwMDAwIiwgIiMzMzMzQ0MiKQoKZ2dwbG90KG9udF9lYWJfZGF0YSwgYWVzKHggPSB5ZWFyLCBmaWxsID0gcmVzdWx0KSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAiY291bnQiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDAyLCAyMDIwLCBieSA9IDIpKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmVzdWx0X2NvbG91cikgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBUaHJvdWdob3V0IFRpbWUiLCB4ID0gIlllYXIiLCB5ID0gIk9ic2VydmF0aW9uIENvdW50IiwgZmlsbCA9ICJEZXRlY3Rpb24gUmVzdWx0IikKYGBgCkFzIHlvdSBjYW4gc2VlLCB0aGUgb2JzZXJ2YXRpb25zIGFyZSBza2V3ZWQgdGhyb3VnaCB0aGUgeWVhcnMuIFRoZSBncmVhdGVzdCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGhhcHBlbmVkIGJldHdlZW4gdGhlIHllYXJzIDIwMDMgYW5kIDIwMTAsIHdoaWNoIGNvcnJlc3BvbmRzIHdpdGggc29tZSBvZiB0aGUgZmlyc3QgcmVjb3JkZWQgaW5jaWRlbmNlcyBvZiB0aGUgRUFCIGluIE5vcnRoIEFtZXJpY2EuIFRoZSBtb3N0LWltcG9ydGFudCB0YWtlYXdheSBmcm9tIHRoaXMgZ3JhcGggaXMgdGhlIGZyZXF1ZW5jeSBvZiBvYnNlcnZhdGlvbnMgd2l0aGluIHRoaXMgZGF0YXNldCBjaGFuZ2VkIHNpZ25pZmljYW50bHkgbW9yZSBvdmVyIHRpbWUgdGhhbiB0aGUgYWJ1bmRhbmNlIG9mIEVBQnMgZGlkLiBGdXJ0aGVybW9yZSwgdGhpcyBjaGFuZ2UgaW4gb2JzZXJ2YXRpb24gZnJlcXVlbmN5IG92ZXIgdGhlIHllYXJzIG1ha2VzIGl0IGhhcmRlciB0byBjb21wYXJlIGFuZCBjb250cmFzdCBkZXRlY3Rpb24gcmF0ZSB0aHJvdWdoIHRoZSB5ZWFycy4KCiMjIyBNb2RlbCAyOiBMYXRpdHVkZSArIExvbmdpdHVkZQoKYGBge3IgZmlnLmFzcCA9IDAuNSwgZmlnLndpZHRoID0gOC41fQpnZ3Bsb3Qob250X2VhYl9kYXRhLCBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlLCBjb2xvciA9IHJlc3VsdCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjgsIGFscGhhID0gMC42KSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJlc3VsdF9jb2xvdXIpICsKICBsYWJzKHRpdGxlID0gIkVBQiBEZXRlY3Rpb24gaW4gT250YXJpbyBieSBMb25naXR1ZGUgJiBMYXRpdHVkZSIsIHggPSAiTG9uZ2l0dWRlIiwgeSA9ICJMYXRpdHVkZSIsIGNvbG9yID0gIkRldGVjdGlvbiBSZXN1bHQiKQpgYGAKRUFCIGRldGVjdGlvbiBpcyBjb25jZW50cmF0ZWQgaW4gb25lIGdlbmVyYWwgYXJlYSEKCmBgYHtyIGZpZy5hc3AgPSAwLjUsIGZpZy53aWR0aCA9IDguNX0KZ2dwbG90KG9udF9lYWJfZGF0YSwgYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSwgY29sb3IgPSBjb21tdW5pdHlfdHlwZSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjgsIGFscGhhID0gMC42KSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG91cikgKwogIGxhYnModGl0bGUgPSAiQ29tbXVuaXR5IFR5cGUgaW4gT250YXJpbyBieSBMb25naXR1ZGUgJiBMYXRpdHVkZSIsIHggPSAiTG9uZ2l0dWRlIiwgeSA9ICJMYXRpdHVkZSIsIGNvbG9yID0gIkNvbW11bml0eSBUeXBlIikKYGBgClRoZXJlIElTIGEgY29ycmVsYXRpb24gYmV0d2VlbiBjb29yZGluYXRlcyBhbmQgY29tbXVuaXR5IHR5cGUKCmBgYHtyIGZpZy5hc3AgPSAwLjUsIGZpZy53aWR0aCA9IDguNX0KZ2dwbG90KG9udF9lYWJfZGF0YSwgYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSwgY29sb3IgPSBhdmdfdGVtcCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLCBhbHBoYSA9IDAuMykgKwogIHRoZW1lX2J3KCkgKyAgCiAgbGFicyh0aXRsZSA9ICJBbm51YWwgQXZlcmFnZSBUZW1wZXJhdHVyZSBpbiBPbnRhcmlvIGJ5IExvbmdpdHVkZSAmIExhdGl0dWRlIiwgeCA9ICJMb25naXR1ZGUiLCB5ID0gIkxhdGl0dWRlIiwgY29sb3IgPSAiQXZlcmFnZSBBbm51YWwgVGVtcGVyYXR1cmUgKMuaQykiKQpgYGAKCgojIyMgTW9kZWwgMzogQ29tbXVuaXR5IFR5cGUKCmBgYHtyIGZpZy5hc3AgPSAwLjUsIGZpZy53aWR0aCA9IDguNX0Kb250X2VhYl9kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCBmaWxsID0gY29tbXVuaXR5X3R5cGUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMS4yKSArIAogIGZhY2V0X3dyYXAofnJlc3VsdCwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDIsIDIwMjAsIGJ5ID0gMikpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG91cikgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBieSBZZWFyIGFuZCBDb21tdW5pdHkgVHlwZSIsIHggPSAiWWVhciIsIHkgPSAiTnVtYmVyIG9mIE9ic2VydmF0aW9ucyIsIAogICAgICAgZmlsbCA9ICJDb21tdW5pdHkgVHlwZSIpCmBgYApOb3RlIHRoZSBkaWZmZXJlbmNlcyBpbiB5LWF4aXMgc2NhbGVzIGJldHdlZW4gIkRldGVjdGVkIiBhbmQgIk5vdCBEZXRlY3RlZCIsIGFzIHdlbGwgYXMgdGhlIHNpZ25pZmljYW50bHkgaGlnaGVyIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gdGhlIGVhcmxpZXIgaGFsZiBvZiB0aGUgZGF0YXNldC4KCmBgYHtyfQpnZ3Bsb3Qob250X2VhYl9kYXRhLCBhZXMoeCA9IHJlc3VsdCwgeSA9IHllYXIsIGZpbGwgPSByZXN1bHQpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMC42LCBhbHBoYSA9IDAuNCkgKyBmYWNldF93cmFwKH5jb21tdW5pdHlfdHlwZSkgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHJlc3VsdF9jb2xvdXIpICsKICBsYWJzKHRpdGxlID0gIkVBQiBEZXRlY3Rpb24gYnkgWWVhciBhbmQgQ29tbXVuaXR5IFR5cGUiLCB4ID0gIiIsIHkgPSAiWWVhciIsIGZpbGwgPSAiRGV0ZWN0aW9uIFJlc3VsdCIpCmBgYAoKYGBge3J9CmdncGxvdChvbnRfZWFiX2RhdGEsIGFlcyh4ID0gcmVzdWx0LCB5ID0geWVhciwgZmlsbCA9IHJlc3VsdCkpICsgCiAgZ2VvbV92aW9saW4oKSArIAogIGZhY2V0X3dyYXAofmNvbW11bml0eV90eXBlKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmVzdWx0X2NvbG91cikgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBieSBZZWFyIGFuZCBDb21tdW5pdHkgVHlwZSIsIHggPSAiIiwgeSA9ICJZZWFyIiwgZmlsbCA9ICJEZXRlY3Rpb24gUmVzdWx0IikKYGBgCmBgYHtyfQpnZ3Bsb3Qob250X2VhYl9kYXRhLCBhZXMoeCA9IGNvbW11bml0eV90eXBlLCB5ID0geWVhciwgZmlsbCA9IGNvbW11bml0eV90eXBlKSkgKyAKICBnZW9tX3Zpb2xpbigpICsgCiAgZmFjZXRfd3JhcCh+cmVzdWx0KSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3VyKSArCiAgbGFicyh0aXRsZSA9ICJFQUIgRGV0ZWN0aW9uIGJ5IFllYXIgYW5kIENvbW11bml0eSBUeXBlIiwgeCA9ICIiLCB5ID0gIlllYXIiLCBmaWxsID0gIkNvbW11bml0eSBUeXBlIikKYGBgCmBgYHtyfQpnZ3Bsb3Qob250X2VhYl9kYXRhLCBhZXMoeCA9IHllYXIsIHkgPSBjb21tdW5pdHlfdHlwZSwgZmlsbCA9IGNvbW11bml0eV90eXBlKSkgKyAKICBnZW9tX3Zpb2xpbigpICsgCiAgZmFjZXRfd3JhcCh+cmVzdWx0KSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDAyLCAyMDIwLCBieSA9IDIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXIpICsKICBsYWJzKHRpdGxlID0gIkVBQiBEZXRlY3Rpb24gYnkgWWVhciBhbmQgQ29tbXVuaXR5IFR5cGUiLCB4ID0gIlllYXIiLCB5ID0gIiIsIGZpbGwgPSAiQ29tbXVuaXR5IFR5cGUiKQpgYGAKCiMjIyBDb21tdW5pdGllcyBEb21pbmF0aW5nIHRoZSBPYnNlcnZhdGlvbnMKCmBgYHtyfQpjb21tdW5pdHlfY291bnQgPC0gb250X2VhYl9kYXRhICU+JSAKICBjb3VudChjb21tdW5pdHksIHd0ID0gTlVMTCwgc29ydCA9IFRSVUUpCnRvdGFsX2RhdGFmcmFtZSA8LSBjYmluZCh0ZW1wZXJhdHVyZV9kYXRhLCBjb21tdW5pdHlfY291bnQpCm1vc3Rfb2JzZXJ2YXRpb25zIDwtIHRvdGFsX2RhdGFmcmFtZSAlPiUgCiAgZmlsdGVyKG4gPj0gMjAwKQoKZ2dwbG90KG1vc3Rfb2JzZXJ2YXRpb25zLCBhZXMoeCA9IGNvbW11bml0eSwgeSA9IG4pKSArIAogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsKICBsYWJzKHggPSAiQ29tbXVuaXR5IiwgeSA9ICJPYnNlcnZhdGlvbnMgcGVyIENvbW11bml0eSIsIHRpdGxlID0gIk51bWJlciBvZiBPYnNlcnZhdGlvbnMgZnJvbSBFYWNoIENvbW11bml0eSAobiDiiaUgMjAwKSIpCmBgYApDaGF0aGFtLUtlbnQgRGl2aXNpb24gKHJ1cmFsKQoKYGBge3J9Cm9udF9lYWJfZGF0YSAlPiUgCiAgZmlsdGVyKGNvbW11bml0eSA9PSAiQ0hBVEhBTS1LRU5UIERJVklTSU9OIikgJT4lIApnZ3Bsb3QoYWVzKHggPSB5ZWFyLCBmaWxsID0gcmVzdWx0KSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAiY291bnQiKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmVzdWx0X2NvbG91cikgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBieSBZZWFyIGluIHRoZSBDaGF0aGFtLUtlbnQgRGl2aXNpb24iLCB4ID0gIlllYXIiLCB5ID0gIk51bWJlciBvZiBPYnNlcnZhdGlvbnMiLCBmaWxsID0gIkRldGVjdGlvbiBSZXN1bHQiKQpgYGAKT3VyIGRhdGFzZXQgaXMgZG9taW5hdGVkIGJ5IGEgY291cGxlIG9mIGNvbW11bml0aWVzIGVzcGVjaWFsbHkgZHVyaW5nIHRoZSBlYXJseSB5ZWFycyBvZiBkYXRhIGNvbGxlY3Rpb24uCgoKIyMjIE1vZGVsIDQ6IFRlbXBlcmF0dXJlCgpgYGB7ciBmaWcuYXNwID0gMC41LCBmaWcud2lkdGggPSA4LjV9CmdncGxvdChvbnRfZWFiX2RhdGEsIGFlcyh4ID0geWVhciwgeSA9IGF2Z190ZW1wLCBjb2xvciA9IHJlc3VsdCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJnbG0iLCBmYW1pbHkgPSAiYmlub21pYWwiLCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJlc3VsdF9jb2xvdXIpICsKICB0aGVtZV9idygpICsKICBsYWJzKHRpdGxlID0gIkVBQiBEZXRlY3Rpb24gVGhyb3VnaCBUaW1lIGFzIGEgRnVuY3Rpb24gb2YgVGVtcGVyYXR1cmUiLCB4ID0gIlllYXIiLCB5ID0gIkF2ZXJhZ2UgVGVtcGVyYXR1cmUgKMuaQykiLCBjb2xvciA9ICJEZXRlY3Rpb24gUmVzdWx0IikKYGBgCgoKYGBge3IgZmlnLmFzcCA9IDAuNSwgZmlnLndpZHRoID0gMTV9CmdncGxvdChvbnRfZWFiX2RhdGEsIGFlcyh4ID0gY29tbXVuaXR5LCB5ID0gYXZnX3RlbXAsIGNvbG9yID0gcmVzdWx0KSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJlc3VsdF9jb2xvdXIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBUaHJvdWdoIFRpbWUgYXMgYSBGdW5jdGlvbiBvZiBUZW1wZXJhdHVyZSIsIHggPSAiWWVhciIsIHkgPSAiQXZlcmFnZSBUZW1wZXJhdHVyZSAoy5pDKSIsIGNvbG9yID0gIkRldGVjdGlvbiBSZXN1bHQiKQpgYGAKCgojIyMgTW9kZWwgNTogQ29tbXVuaXR5IFR5cGUgQU5EIFRlbXBlcmF0dXJlCgpgYGB7ciBmaWcuYXNwID0gMC41LCBmaWcud2lkdGggPSA4LjV9CmdncGxvdChvbnRfZWFiX2RhdGEsIGFlcyh4ID0geWVhciwgeSA9IGF2Z190ZW1wLCBjb2xvciA9IHJlc3VsdCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH5jb21tdW5pdHlfdHlwZSkgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwMiwgMjAyMCwgYnkgPSAyKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJlc3VsdF9jb2xvdXIpICsKICBsYWJzKHRpdGxlID0gIkVBQiBEZXRlY3Rpb24gYnkgWWVhciwgVGVtcGVyYXR1cmUgYW5kIENvbW11bml0eSBUeXBlIiwgeCA9ICJZZWFyIiwgeSA9ICJBdmVyYWdlIEFubnVhbCBUZW1wZXJhdHVyZSAoy5pDKSIsIGNvbG9yID0gIkRldGVjdGlvbiBSZXN1bHQiKQpgYGAKCmBgYHtyfQpjb2xvdXIgPC0gYyhydXJhbCA9ICJmb3Jlc3RncmVlbiIsIHVyYmFuID0gImRhcmtncmV5IikKCmdncGxvdChvbnRfZWFiX2RhdGEsIGFlcyh4ID0geWVhciwgeSA9IGF2Z190ZW1wLCBjb2xvciA9IGNvbW11bml0eV90eXBlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+cmVzdWx0KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG91cikgKwogIHRoZW1lX2J3KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDIsIDIwMjAsIGJ5ID0gMikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRUFCIERldGVjdGlvbiBieSBZZWFyLCBUZW1wZXJhdHVyZSBhbmQgQ29tbXVuaXR5IFR5cGUiLCB4ID0gIlllYXIiLCB5ID0gIkF2ZXJhZ2UgQW5udWFsIFRlbXBlcmF0dXJlICjLmkMpIiwgY29sb3IgPSAiQ29tbXVuaXR5IFR5cGUiKQpgYGAKCmBgYHtyfQpnZ3Bsb3Qob250X2VhYl9kYXRhLCBhZXMoeCA9IGF2Z190ZW1wLCB5ID0gcmVzdWx0LCBmaWxsID0gY29tbXVuaXR5X3R5cGUpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3VyKSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZSA9ICJFQUIgRGV0ZWN0aW9uIGJ5IFllYXIsIFRlbXBlcmF0dXJlIGFuZCBDb21tdW5pdHkgVHlwZSIsIHggPSAiVGVtcGVyYXR1cmUiLCB5ID0gIkF2ZXJhZ2UgQW5udWFsIFRlbXBlcmF0dXJlICjLmkMpIiwgY29sb3IgPSAiQ29tbXVuaXR5IFR5cGUiKQpgYGAKCmBgYHtyfQprcnVza2FsLnRlc3QocmVzdWx0IH4gYXZnX3RlbXAqY29tbXVuaXR5LAogICAgICAgICAgICAgZGF0YSA9IG9udF9lYWJfZGF0YSkKYGBgCgpgYGB7cn0KdGVtcF9tb2RlbCA8LSBnbG0oYXMuZmFjdG9yKHJlc3VsdCl+IGF2Z190ZW1wICsgKDF8Y29tbXVuaXR5KSwgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IG9udF9lYWJfZGF0YSkKc3VtbWFyeSh0ZW1wX21vZGVsKQpgYGAKCgoKCgoKCgo=